// Alternate Realms - Item Header
// Copyright 2006 Mike Behlen

// FILE DESCRIPTION:
// This file declares everything having to do with items, including
// the Item class, the specific item types in the form of derived
// classes, and groups of items implemented with a linked list.

// TODO:
// Nothing :)

using namespace std;

enum { ITEM, WEAPON, ARMOR };

class Item {
public:
  Item (string iname, short icost, short iweight, bool icarry);
  virtual ~Item () {}
  
  string getName () { return name; }
  short getCost () { return cost; }
  short getWeight () { return weight; }
  bool canCarry () { return carry; }
  virtual short getItemType () { return ITEM; }
protected:
  string name;
  short cost;
  short weight;  // Most things should be 1
  bool carry;   // false if you can't carry it
};

Item::Item (string iname, short icost, short iweight, bool icarry) :
  name(iname),
  cost(icost),
  weight(iweight),
  carry(icarry)
{}

class Weapon : public Item {
public:
  Weapon(string, short, short, bool, short, short, short, short);
  virtual ~Weapon() {}

  short getDamage () { return damage; }
  short getDamageModifier () { return damagemodifier; }
  short getType () { return type; }
  short getRange () { return range; }
  virtual short getItemType () { return WEAPON; }
protected:
  short damage;
  short damagemodifier;
  short type;
  short range;
};

Weapon::Weapon (string iname, short icost, short iweight, bool icarry, short idamage, short idamagemodifier, short itype, short irange) :
  Item(iname, icost, iweight, icarry),
  damage(idamage),
  damagemodifier(idamagemodifier),
  type(itype),
  range(irange)
{}
  

class Armor : public Item {
public:
  Armor(string, short, short, bool, short, short);
  virtual ~Armor() {}
  
  short getAC() { return ac; }
  short getType() { return type; }
  virtual short getItemType () { return ARMOR; }
protected:
  short ac;
  short type;
};

Armor::Armor (string iname, short icost, short iweight, bool icarry, short iac, short itype) :
  Item(iname, icost, iweight, icarry),
  ac(iac),
  type(itype)
{}




// Basic Inventory Node class
class InventoryNode {
public:
  InventoryNode () {}
  virtual ~InventoryNode () {}
  virtual InventoryNode * addItem (Item *theItem) = 0;
  virtual void listItems () = 0;
  virtual void delItem (string) = 0;
  virtual int countItems (int) = 0;
  virtual Item getItem_name (string) = 0;
  virtual Item getItem_order (int, int) = 0;
private:
};


// Body of the Inventory
class InventoryBody : public InventoryNode {
public:
  InventoryBody (Item *theItem, InventoryNode *theNextNode) { myItem = theItem; nextNode = theNextNode; }
  virtual ~InventoryBody () { delete nextNode; } //delete nextNode; delete myItem; }
  virtual InventoryNode * addItem (Item *theItem);
  virtual void delItem (string) {}
  virtual Item getItem_name (string theItem) { 
    if (myItem->getName() == theItem) return *myItem; 
    return nextNode->getItem_name(theItem); }
  virtual Item getItem_order (int reqItem, int thisItem) {
    thisItem++;
    if (reqItem == thisItem) return *myItem; 
    return nextNode->getItem_order(reqItem, thisItem); }
  virtual int countItems (int numItems) { return nextNode->countItems(numItems + 1); }
  virtual void listItems ();
private:
  Item *myItem;
  InventoryNode *nextNode;
};

InventoryNode * InventoryBody::addItem (Item *theItem) {
  InventoryBody *newItem = new InventoryBody (theItem, this);
  return newItem;
}

void InventoryBody::listItems () {
  std::cout << myItem->getName() << " -- " << myItem->getCost() << "\n";
  nextNode->listItems();
}


// Tail of the Inventory
class InventoryTail : public InventoryNode {
public:
  InventoryTail () {}
  virtual ~InventoryTail () {}
  virtual InventoryNode * addItem (Item *theItem);
  virtual void delItem (string theItem) {}
  virtual Item getItem_name (string theItem) { }
  virtual Item getItem_order (int reqItem, int thisItem) { }
  virtual void listItems () {}
  virtual int countItems (int numItems) { return numItems; }
};

InventoryNode * InventoryTail::addItem (Item *theItem) {
  InventoryBody *newItem = new InventoryBody (theItem, this);
  return newItem;
}


// Head of the Inventory
class InventoryHead : public InventoryNode {
public:
  InventoryHead () { nextNode = new InventoryTail; }
  virtual ~InventoryHead () { delete nextNode; }
  virtual InventoryNode * addItem (Item *theItem) { nextNode = nextNode->addItem(theItem); }
  virtual void delItem (string theItem) {}
  virtual Item getItem_name (string theItem) { return nextNode->getItem_name(theItem); }
  virtual Item getItem_order (int reqItem, int thisItem) { return nextNode->getItem_order(reqItem, -1); }
  virtual void listItems () { nextNode->listItems(); }
  virtual int countItems (int numItems) { return nextNode->countItems(-1); /* This so the first item is item 0 */}


private:
  InventoryNode *nextNode;
};


// Inventory Class
class Inventory {
public:
  Inventory () { headNode = new InventoryHead; }
  ~Inventory () { delete headNode; }
  void addItem (Item *theItem) { headNode->addItem(theItem); }
  void delItem (string theItem) {}
  Item getItem_name (string theItem) { return headNode->getItem_name(theItem); }
  Item getItem_order (int reqItem) { return headNode->getItem_order(reqItem, -1); }
  void listItems () { headNode->listItems(); }
  int countItems() { return headNode->countItems(1234); /* This number gets dumped on the floor */}
private:  
  InventoryHead *headNode;
};
